package com.snake

import android.content.Context
import android.media.MediaPlayer
import android.os.Handler
import android.os.Handler.Callback
import android.os.Looper
import android.os.Message

import androidx.compose.foundation.Canvas
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.draggable2D
import androidx.compose.foundation.gestures.rememberDraggable2DState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableIntState
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset

import com.snake.SnakeBody.Type

import java.util.Random
import java.util.Timer
import java.util.TimerTask

import kotlin.math.abs

// 游戏
class Game: Callback {
    /**
     * 定时器任务的构造方法。
     * @param callback  回调
     */
    private class GameTimerTask(callback: Callback): TimerTask() {
        private val mCallback = Handler(Looper.getMainLooper(), callback)   // 回调

        /**
         * 定时器事件的响应方法。
         */
        override fun run() {
            mCallback.sendEmptyMessage(Const.UM_TIMER)
        }
    }

    // 状态
    enum class Status {
        CREATING,   // 正在创建游戏物体
        END,        // 已结束
        LOST,       // 游戏失败
        PAUSED,     // 暂停中
        PLAYING,    // 游戏中
        STARTING,   // 正在开始
        WON         // 游戏胜利
    }

    private var mApple: SnakeBody? = null                       // 果子
    private lateinit var mDifficulty: MutableIntState           // 难度
    private lateinit var mEnableMusic: MutableState<Boolean>    // 音乐开关
    private val mMusicPlayer: MediaPlayer                       // 音乐播放者
    private val mRandom: Random                                 // 随机数生成器
    private lateinit var mScore: MutableIntState                // 得分
    private var mSnake: Snake? = null                           // 蛇
    private lateinit var mStatus: MutableState<Status>          // 状态
    private val mTimer: Timer                                   // 定时器
    private var mTimerTask: TimerTask? = null                   // 定时器任务

    /**
     * 构造方法。
     * @param context   设备环境
     */
    constructor(context: Context) {
        // 初始化成员
        mMusicPlayer = MediaPlayer.create(context, R.raw.music)
        mMusicPlayer.isLooping = true
        mRandom = Random()
        mTimer = Timer()
    }

    /**
     * 在随机位置创建果子。
     */
    @Composable
    private fun CreateApple() {
        var point = Offset.Zero
        var x = 0f
        var y = 0f
        var used: Boolean

        // 创建果子
        do {
            // 取 x、y 的随机值
            x = (mRandom.nextInt(Const.GAME_BOARD_GRID_COUNT_H - 2) + 1).toFloat()
            y = (mRandom.nextInt(Const.GAME_BOARD_GRID_COUNT_V - 2) + 1).toFloat()
            point = Offset(x, y)
            used = this.pointIsUsed(point)
        } while (used)
        mApple = SnakeBody(Type.APPLE)
        mApple!!.Init(point)
    }

    /**
     * 获取难度。
     */
    val difficulty: Int
        get() = mDifficulty.intValue

    /**
     * 游戏结束。
     * @param status    游戏状态
     */
    private fun gameOver(status: Status) {
        // 设置游戏状态
        mStatus.value = status

        // 停止定时器
        mTimerTask!!.cancel()

        // 停止播放音乐
        if (mEnableMusic.value) {
            try {
                mMusicPlayer.stop()
                mMusicPlayer.prepare()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    /**
     * 创建游戏区域。
     * @param modifier  修饰符
     */
    @OptIn(ExperimentalFoundationApi::class)
    @Composable
    fun GameBoard(modifier: Modifier) {
        // 初始化成员
        mDifficulty = remember {
            mutableIntStateOf(1)
        }
        mEnableMusic = remember {
            mutableStateOf(false)
        }
        mScore = remember {
            mutableIntStateOf(0)
        }
        mStatus = remember {
            mutableStateOf(Status.END)
        }
        if (mStatus.value == Status.STARTING) {
            mSnake = Snake()
            mSnake!!.Init()
            this.CreateApple()
            mStatus.value = Status.PLAYING
        }
        if (mStatus.value == Status.CREATING) {
            this.CreateApple()
            mStatus.value = Status.PLAYING
        }

        // 创建游戏区域
        Canvas(modifier
            .background(Const.GAME_BOARD_COLOR)
            .draggable2D(
                state = rememberDraggable2DState {},
                onDragStopped = {
                    if (abs(it.x) > abs(it.y)) {
                        if (it.x < 0) {
                            this.onFling(Const.DIRECTION_LEFT)
                        } else {
                            this.onFling(Const.DIRECTION_RIGHT)
                        }
                    } else if (it.y < 0) {
                        this.onFling(Const.DIRECTION_UP)
                    } else {
                        this.onFling(Const.DIRECTION_DOWN)
                    }
                }
            )
        ) {
            if (mStatus.value == Status.PLAYING || mStatus.value == Status.PAUSED) {
                mSnake!!.draw(this)
                mApple?.draw(this)
            }
        }
    }

    /**
     * 自定义事件的响应方法。
     * @param message   事件
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    override fun handleMessage(message: Message): Boolean {
        this.onTimer()
        return true
    }

    /**
     * 判断是否允许播放音乐。
     */
    val isMusicEnabled: Boolean
        get() {
            if (::mEnableMusic.isInitialized) {
                return mEnableMusic.value
            }
            return false
        }

    /**
     * 判断是否胜利。
     */
    private val isWon: Boolean
        get() = mScore.intValue >= Const.WIN_NUMBER

    /**
     * 滑动手势的响应方法。
     * @param direction 方向
     * @return 事件在此被处理则返回 true，否则返回 false
     */
    fun onFling(direction: Int): Boolean {
        if (mStatus.value != Status.PLAYING) {
            return false
        }
        mSnake!!.turn(direction)
        return true
    }

    /**
     * 定时器事件的响应方法。
     */
    fun onTimer() {
        // 移动蛇
        val isDead = mSnake!!.move()
        if (isDead) {
            this.gameOver(Status.LOST)
            return
        }

        // 检查是否碰到果子
        val head: SnakeBody = mSnake!!.head
        if (head.position == mApple!!.position) {
            // 碰到果子，将果子加入蛇链表
            mSnake!!.eat(mApple!!)
            mStatus.value = Status.CREATING
            mScore.intValue++

            // 判断是否胜利
            if (this.isWon) {
                this.gameOver(Status.WON)
                return
            }

            // 判断是否达到增加难度的条件
            if (mScore.intValue % Const.DIFF_BASE == 0 && mDifficulty.intValue != Const.DIFF_MAX) {
                mDifficulty.intValue++
                mTimerTask!!.cancel()
                val elapse = Const.TIMER_INIT - Const.TIMER_GROW * (mDifficulty.intValue - 1)
                mTimerTask = GameTimerTask(this)
                mTimer.schedule(mTimerTask, elapse, elapse)
            }
        }
    }

    /**
     * 游戏暂停。
     */
    fun pause() {
        if (mStatus.value == Status.PLAYING) {
            // 停止定时器
            mTimerTask!!.cancel()

            // 停止播放音乐
            if (mEnableMusic.value) {
                mMusicPlayer.pause()
            }

            // 将状态设置为已暂停
            mStatus.value = Status.PAUSED
        } else if (mStatus.value == Status.PAUSED) {
            // 开启定时器
            mTimerTask = GameTimerTask(this)
            val elapse = Const.TIMER_INIT - Const.TIMER_GROW * (mDifficulty.intValue - 1)
            mTimer.schedule(mTimerTask, elapse, elapse)

            // 播放音乐
            if (mEnableMusic.value) {
                mMusicPlayer.start()
            }

            // 将状态设置为游戏中
            mStatus.value = Status.PLAYING
        }
    }

    /**
     * 播放音乐。
     * @return 正在播放音乐则为 true，否则为 false
     */
    fun playMusic(): Boolean {
        mEnableMusic.value = !mEnableMusic.value

        if (mEnableMusic.value) {
            if (mStatus.value == Status.PLAYING) {
                mMusicPlayer.start()
            }
        } else {
            mMusicPlayer.pause()
        }

        return mEnableMusic.value
    }

    /**
     * 判断某个点是否被占用。
     * @param point 点
     * @return 被占用了则返回 true，否则返回 false
     */
    private fun pointIsUsed(point: Offset): Boolean {
        // 检查点是否在蛇上
        if (mSnake != null) {
            if (mSnake!!.pointIsOnMe(point)) {
                return true
            }
        }

        // 检查点是否在果子上
        if (mApple != null) {
            return mApple!!.position == point
        }

        return false
    }

    /**
     * 获取得分。
     */
    val score: Int
        get() = mScore.intValue

    /**
     * 游戏开始。
     */
    fun start() {
        // 将状态设置为开始中
        mStatus.value = Status.STARTING

        // 重置难度
        mDifficulty.intValue = 1

        // 重置分数
        mScore.intValue = 0

        // 开启定时器
        if (mStatus.value != Status.PAUSED || mStatus.value != Status.END) {
            mTimerTask?.cancel()
        }
        mTimerTask = GameTimerTask(this)
        mTimer.schedule(mTimerTask, Const.TIMER_INIT, Const.TIMER_INIT)

        // 播放音乐
        if (mEnableMusic.value) {
            mMusicPlayer.start()
        }
    }

    /**
     * 获取游戏状态。
     */
    var status = Status.END
        get() {
            if (::mStatus.isInitialized) {
                return mStatus.value
            }
            return Status.END
        }
        private set
}
